//
// Created by seeed on 25-8-14.
//

#include <esp32-hal.h>
#include <Wire.h>
#include "myTask.h"
#include <cstdio>
#include "global/GData.h"
#include "global/GObject.h"
#include "../../resource/bmp.h"
#include "net/ESP_NOW.h"

// 任务句柄
TaskHandle_t Mobility_Task_Handle = NULL;    // 人物检测处理任务 句柄
TaskHandle_t LedMatrix_Task_Handle = NULL;  // LED矩阵屏显示任务 句柄
TaskHandle_t Ultrasonic_Task_Handle = NULL;  // 超声波测距任务 句柄
TaskHandle_t Relay_Task_Handle = NULL;       // 继电器任务 句柄
TaskHandle_t buzzer_Task_Handle = NULL;     // 蜂鸣器任务 句柄


// 人物检测处理任务(接收运动传感器通知)
[[noreturn]] void Mobility_Task_Func(void *pvParameters) {
    printf("Mobility_Task_Start>>\n");
    while (true) {
        xTaskNotifyWait(ULONG_MAX, ULONG_MAX, NULL, portMAX_DELAY);     // 等待通知
        printf("PIR Motion Detected!\n");
        PirEvent_Flag = true;
        vTaskDelay(pdMS_TO_TICKS(1000));   // xxS后清除事件
        PirEvent_Flag = false;
    }
}

// LED矩阵屏显示任务
[[noreturn]] void LedMatrix_Task_Func(void *pvParameters) {
    printf("LedMatrix_Task_Start>>\n");
    while ( true){
        ledMatrix0.clear();
        if(Bell_Flag){
            printf("Bell_Flag");
            ledMatrix0.drawSprite(0, 0, BELL, 8, 8);
        }else if(Approaching_Flag){
            printf("Approaching_Flag");
            ledMatrix0.drawSprite(0, 0, ARROW1, 8, 8);

        }else if(PirEvent_Flag || Detected_Flag){
            printf("PirEvent_Flag || Detected_Flag : %d, %d", PirEvent_Flag, Detected_Flag);
            ledMatrix0.drawSpriteLoopScrolling(0, 0, ARROW2, 8, 8, 3, 8, 100);
        }else{
            ledMatrix0.drawSprite(0, 0, face, 8, 8);
        }
        ledMatrix0.update();
        delay(100);
    }
}

// 继电器任务
[[noreturn]] void Relay_Task_Func(void *pvParameters) {
    printf("Relay_Task_Start>>\n");
    while ( true){
        if(Bell_Flag){
            relay0.on();
        }else{
            relay0.off();
        }
        vTaskDelay(pdMS_TO_TICKS(200));
    }
}

// 蜂鸣器任务 (ESP-NOW数据发送)
[[noreturn]] void buzzer_Task_Func(void *pvParameters) {
    printf("buzzer_Task_Start>>\n");
    while ( true){
        if(Bell_Flag){
            espNowManager.sendData((uint8_t*)bell_cmd, bell_cmd_len);   // 发送铃声命令
            for(int i = 0; i < 2; i++){     // 3声
                buzzer0.on();
                vTaskDelay(pdMS_TO_TICKS(100));
                buzzer0.off();
                vTaskDelay(pdMS_TO_TICKS(100));
            }
            vTaskDelay(pdMS_TO_TICKS(1000));
        }
        vTaskDelay(pdMS_TO_TICKS(200));
    }
}

// 超声波测距任务
[[noreturn]] void Ultrasonic_Task_Func(void *pvParameters) {
    printf("Ultrasonic_Task_Start>>\n");
    while ( true){
        Ultrasonic_distance = ultrasonic0.getDistance();
        // 检测触发铃声
        if(0 < Ultrasonic_distance && Ultrasonic_distance < BELL_Trigger_Distance) Bell_Flag = true; else Bell_Flag = false;
        // 检测接近
        if(BELL_Trigger_Distance < Ultrasonic_distance && Ultrasonic_distance < BELL_Approaching_Distance) Approaching_Flag = true; else Approaching_Flag = false;
        // 人物检测
        if(BELL_Approaching_Distance < Ultrasonic_distance && Ultrasonic_distance < BELL_Detected_Distance) Detected_Flag = true; else Detected_Flag = false;
        vTaskDelay(pdMS_TO_TICKS(500));
    }
}

// 任务初始化
void Task_init() {
    // 创建人物接近处理任务（参数：任务函数，任务名，栈大小，参数，优先级，任务句柄）
    xTaskCreate( Mobility_Task_Func, "Mobility_Task", 2048, NULL, 2, &Mobility_Task_Handle );
    // 创建LED矩阵屏显示任务
    xTaskCreate( LedMatrix_Task_Func, "LedMatrix_Task", 2048, NULL, 1, &LedMatrix_Task_Handle );
    // 创建超声波测距任务
    xTaskCreate( Ultrasonic_Task_Func, "Ultrasonic_Task", 2048, NULL, 3, &Ultrasonic_Task_Handle );
    // 创建继电器任务
    xTaskCreate( Relay_Task_Func, "Relay_Task", 2048, NULL, 1, &Relay_Task_Handle );
    // 创建蜂鸣器任务
    xTaskCreate( buzzer_Task_Func, "buzzer_Task", 2048, NULL, 1, &buzzer_Task_Handle );
}

// 不能使用[[noreturn]] 这里是C语言
extern "C" void vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName) {
    portDISABLE_INTERRUPTS();
    Serial.printf("\n!!! Stack Overflow !!!\nTask: %s\n", pcTaskName);
    while (true) {
        delay(1000);
        Serial.println("System Halted. Reset Manually.");
    }
}

